%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  Copyright by Wenliang Du.                                       %%
%%  This work is licensed under the Creative Commons                %%
%%  Attribution-NonCommercial-ShareAlike 4.0 International License. %%
%%  To view a copy of this license, visit                           %%
%%  http://creativecommons.org/licenses/by-nc-sa/4.0/.              %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\commonfolder}{../../common-files}

\input{\commonfolder/header}
\input{\commonfolder/copyright}


\newcommand{\bufFigs}{./Figs}

\lhead{\bfseries SEED Labs -- Buffer Overflow Attack Lab (Server Version)}

\def \code#1 {\fbox{\scriptsize{\texttt{#1}}}}

\begin{document}

\begin{center}
{\LARGE Buffer Overflow Attack Lab (Server Version)}
\end{center}

\seedlabcopyright{2020}


% *******************************************
% SECTION
% ******************************************* 
\section{Overview}


Buffer overflow is defined as the condition in which a program attempts to
write data beyond the boundary of a buffer. This
vulnerability can be used by a malicious user to alter the flow control of
the program, leading to the execution of malicious code.
The objective of this lab is for students to gain practical
insights into this type of vulnerability, and learn how to
exploit the vulnerability in attacks. 


In this lab, students will be given four different servers, each
running a program with a buffer-overflow vulnerability. 
Their task is to develop a scheme to exploit
the vulnerability and finally gain the root privilege on these servers.  
In addition to the attacks, students will also experiment with 
several countermeasures against buffer-overflow attacks.  
Students need to evaluate whether the schemes work or not and explain why. 
This lab covers the following topics:

\begin{itemize}[noitemsep]
\item Buffer overflow vulnerability and attack
\item Stack layout in a function invocation
\item Address randomization, Non-executable stack, and  StackGuard
\item Shellcode. We have a separate lab on how to write shellcode 
from scratch.
\end{itemize}



\paragraph{Readings and videos.}
Detailed coverage of the buffer-overflow attack can be found in the following:

\begin{itemize}
\item Chapter 4 of the SEED Book, \seedbook
\item Section 4 of the SEED Lecture at Udemy, \seedcsvideo
\end{itemize}


\paragraph{Lab environment.} \seedenvironmentC


\paragraph{Note for instructors.}
Instructors can customize this lab by choosing values
for \texttt{L1}, ..., \texttt{L4}. See
Section~\ref{sec:vulnerable_program} for details.
Depending on the background of students and the time allocated
for this lab, instructors can also make the
Level-2, Level-3, and Level-4 tasks (or some of them) optional.
The Level-1 task is sufficient to cover the basics of
the buffer-overflow attacks. Levels 2 to 4
increase the attack difficulties.
All the countermeasure tasks are based on the Level-1 task,
so skipping the other levels does not affect those tasks.




% *******************************************
% SECTION
% *******************************************
\section{Lab Environment Setup} 

Please download the \texttt{Labsetup.zip} file to your VM from the lab’s website, 
unzip it, and you will get a folder called \texttt{Labsetup}. All the files 
needed for this lab are included in this folder.


% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{Turning off Countermeasures} 

Before starting this lab, we need to make sure the 
address randomization countermeasure is turned off; otherwise, the 
attack will be difficult. 
You can do it using the following command:

\begin{lstlisting}
$ sudo /sbin/sysctl -w kernel.randomize_va_space=0
\end{lstlisting}
 

% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{The Vulnerable Program} 
\label{sec:vulnerable_program}

The vulnerable program used in this lab is called
\texttt{stack.c}, which is in the \texttt{server-code} folder.
This program has a buffer-overflow vulnerability,
and your job is to exploit this vulnerability and gain the root privilege.
The code listed below has some non-essential information removed,
so it is slightly different from what you get from the lab setup file.

\begin{lstlisting}[language=C, caption={The vulnerable program \texttt{stack.c}}]
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* Changing this size will change the layout of the stack.
 * Instructors can change this value each year, so students
 * won't be able to use the solutions from the past.
#ifndef BUF_SIZE
#define BUF_SIZE 100
#endif

int bof(char *str)
{
    char buffer[BUF_SIZE];

    /* The following statement has a buffer overflow problem */ 
    strcpy(buffer, str);          (*@\ding{80}@*)

    return 1;
}

int main(int argc, char **argv)
{
    char str[517];

    int length = fread(str, sizeof(char), 517, stdin);
    bof(str);
    fprintf(stdout, "==== Returned Properly ====\n");
    return 1;
}
\end{lstlisting}

The above program has a buffer overflow vulnerability. It 
reads data from the standard input, and then passes the data
to another buffer in the function {\tt bof()}. The 
original input can have a maximum length of \texttt{517} bytes, but the buffer
in {\tt bof()} is only \texttt{BUF\_SIZE} bytes long, which is less than
\texttt{517}. Because {\tt strcpy()} does not check boundaries, 
buffer overflow will occur.

The program will run on a server with the root privilege, and its 
standard input will be redirected to a TCP connection between the
server and a remote user. 
Therefore, the program actually gets its data from a remote user. 
If users can exploit this buffer overflow vulnerability, 
they can get a root shell on the server. 


\paragraph{Compilation.}
To compile the above vulnerable program, we need to 
turn off the StackGuard and the non-executable stack protections 
using the \texttt{-fno-stack-protector} and \texttt{"-z execstack"} options.
The following is an example of the compilation command (the \texttt{L1} environment 
variable sets the value for the \texttt{BUF\_SIZE} constant inside \texttt{stack.c}).   

\begin{lstlisting}
$ gcc -DBUF_SIZE=$(L1) -o stack -z execstack -fno-stack-protector stack.c
\end{lstlisting}

We will compile the \texttt{stack} program into both 32-bit and 64-bit 
binaries. Our pre-built Ubuntu 20.04 VM is a 64-bit VM, but it 
still supports 32-bit binaries. All we need to do is to 
use the \texttt{-m32} option in the \texttt{gcc} command. 
For 32-bit compilation, we also use \texttt{-static} to generate 
a statically-linked binary, which is self-contained and not depending
on any dynamic library, because the 32-bit dynamic libraries 
are not installed in our containers. 


The compilation commands are already provided in \texttt{Makefile}. To compile
the code, you need to type \texttt{make} to execute those commands.
The variables \texttt{L1}, \texttt{L2}, \texttt{L3}, and \texttt{L4} are
set in \texttt{Makefile}; they will be used during the compilation.
After the compilation, we need to copy the binary into
the \texttt{bof-containers} folder, so they can be used by the 
containers. The following commands conduct compilation and 
installation.

\begin{lstlisting}
$ make
$ make install
\end{lstlisting}
 

\paragraph{For instructors (customization).}
To make the lab slightly different from the one offered in the past,
instructors can change the value for \texttt{BUF\_SIZE} by requiring
students to compile the server code using different \texttt{BUF\_SIZE} values.
In \texttt{Makefile}, the \texttt{BUF\_SIZE} value is set by
four variables \texttt{L1}, ..., \texttt{L4}.
Instructors should pick the values for these variables based
on the following suggestions:

\begin{itemize}[noitemsep]
\item \texttt{L1}: pick a number between 100 and 400
\item \texttt{L2}: pick a number between 100 and 200
\item \texttt{L3}: pick a number between 100 and 400
\item \texttt{L4}: pick a number between 20 and 80;
we need to keep this number smaller, to make this level more challenging 
than the previous level. 
\end{itemize}



\paragraph{The Server Program.} 
In the \texttt{server-code} folder, you can find a program called \texttt{server.c}. 
This is the main entry point of the server. It listens to port \texttt{9090}. 
When it receives a TCP connection, it 
invokes the \texttt{stack} program, and sets the TCP connection
as the standard input of the \texttt{stack} program. This way,
when \texttt{stack} reads data from \texttt{stdin}, it actually 
reads from the TCP connection, i.e. the data are provided by
the user on the TCP client side. It is not necessary for 
students to read the source code of \texttt{server.c}.  


% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{Container Setup and Commands}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input{\commonfolder/container/setup}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


\paragraph{Note.} It should be noted that before running 
\texttt{"docker-compose build"} to build the docker
images, we need to compile and copy the server 
code to the \texttt{bof-containers} folder. 
This step is described in Section~\ref{sec:vulnerable_program}.



% *******************************************
% SECTION
% ******************************************* 
\section{Task 1: Get Familiar with the Shellcode}

The ultimate goal of buffer-overflow attacks is to inject
malicious code into the target program, so the code can be
executed using the target program's privilege.
Shellcode is widely used in most code-injection attacks.
Let us get familiar with it in this task.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input{\commonfolder/guidelines/shellcode.tex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


You can find the generic shellcode in the \texttt{shellcode} folder.
Inside, you will see two Python programs, 
\texttt{shellcode\_32.py} and \texttt{shellcode\_64.py}. 
They are for 32-bit and 64-bit shellcode, respectively. 
These two Python programs will
write the binary shellcode to \texttt{codefile\_32}
and \texttt{codefile\_64}, respectively. You can then use 
\texttt{call\_shellcode} to execute the shellcode in them. 


\newcommand{\pointright}{\ding{221}}

\begin{lstlisting}
// Generate the shellcode binary 
$ ./shellcode_32.py    (*@\pointright@*) generate codefile_32
$ ./shellcode_64.py    (*@\pointright@*) generate codefile_64

// Compile call_shellcode.c
$ make                 (*@\pointright@*) generate a32.out and a64.out 

// Test the shellcode 
$ a32.out              (*@\pointright@*) execute the shellcode in codefile_32
$ a64.out              (*@\pointright@*) execute the shellcode in codefile_64
\end{lstlisting}
 

\paragraph{Task.} Please modify the shellcode, so you can
use it to delete a file.  Please include your modified shellcode
in the lab report, as well as your screenshots.



% *******************************************
% SECTION
% *******************************************
\section{Task 2: Level-1 Attack} 


When we start the containers using the included 
\texttt{docker-compose.yml} file, four containers will be 
running, representing four levels of difficulties. 
We will work on Level 1 in this task. 


% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{Server} 

Our first target runs on \texttt{10.9.0.5} (the port 
number is \texttt{9090}), and the vulnerable program \texttt{stack}
is a 32-bit program. 
Let's first send a benign message to this server.
We will see the following messages printed out by the target container (the
actual messages you see may be different).


\begin{lstlisting}
// On the VM (i.e., the attacker machine)
$ echo hello | nc 10.9.0.5 9090
Press Ctrl+C

// Messages printed out by the container
server-1-10.9.0.5 | Got a connection from 10.9.0.1
server-1-10.9.0.5 | Starting stack
server-1-10.9.0.5 | Input size: 6
server-1-10.9.0.5 | Frame Pointer (ebp) inside bof():  0xffffdb88    (*@\ding{80}@*)
server-1-10.9.0.5 | Buffer's address inside bof():     0xffffdb18    (*@\ding{80}@*)
server-1-10.9.0.5 | ==== Returned Properly ====
\end{lstlisting}


The server will accept up to \texttt{517} bytes of the data from the 
user, and that will cause a buffer overflow. Your job 
is to construct your payload to exploit this vulnerability. If 
you save your payload in a file, you can send the payload
to the server using the following command.

\begin{lstlisting}
$ cat <file> | nc 10.9.0.5 9090
\end{lstlisting}

If the server program returns, it will print out \texttt{"Returned Properly"}.
If this message is not printed out, the \texttt{stack} program has probably crashed. 
The server will still keep running, taking new connections.  

For this task, two pieces of information essential for buffer-overflow 
attacks are printed out as hints to students: 
the value of the frame pointer and the address
of the buffer (lines marked by \ding{80}). The frame point register 
called \texttt{ebp} for the x86 architecture and \texttt{rbp} for the x64 architecture.
You can use these two pieces of information to construct 
your payload. 


\paragraph{Added randomness.} We have added a little bit of randomness
in the program, so different students are likely to see different values
for the buffer address and frame pointer. The values only change 
when the container restarts, so as long as you keep the 
container running, you will see the same numbers (the numbers 
seen by different students are still different). This randomness
is different from the address-randomization countermeasure. Its sole
purpose is to make students' work a little bit different. 


% -------------------------------------------
% SUBSECTION
% ------------------------------------------- 
\subsection{Writing Exploit Code and Launching Attack} 

To exploit the buffer-overflow vulnerability in the target program,
we need to prepare a payload, and save it inside a file (we will use 
\texttt{badfile} as the file name in this document). 
We will use a Python program to do that.
We provide a skeleton program called \texttt{exploit.py}, which
is included in the lab setup file. 
The code is incomplete, and students need to replace some of the essential 
values in the code. 


\newcommand{\needtochange}{\ding{73} Need to change \ding{73}}


\begin{lstlisting}[language=python, caption={The skeleton exploit code (\texttt{exploit.py})}]
#!/usr/bin/python3
import sys

# You can copy and paste the shellcode from Task 1
shellcode = (
  ""                     # (*@\needtochange@*)
).encode('latin-1')

# Fill the content with NOP's
content = bytearray(0x90 for i in range(517))

##################################################################
# Put the shellcode somewhere in the payload
start =  0               # (*@\needtochange@*)
content[start:start + len(shellcode)] = shellcode

# Decide the return address value 
# and save it somewhere in the payload
ret    = 0xAABBCCDD      # (*@\needtochange@*)
offset = 0               # (*@\needtochange@*)

# Use 4 for 32-bit address and 8 for 64-bit address
content[offset:offset + 4] = (ret).to_bytes(4,byteorder='little')
##################################################################

# Write the content to a file
with open('badfile', 'wb') as f:
  f.write(content)
\end{lstlisting}


After you finish the above program, run it. This will generate
the contents for \texttt{badfile}. Then feed it to
the vulnerable server. If your exploit is implemented correctly, the 
command you put inside your shellcode will be executed. If your 
command generates some outputs, you should be able to see
them from the container window. Please provide proofs to show that you
can successfully get the vulnerable server to run 
your commands.

\begin{lstlisting}
$./exploit.py   // create the badfile
$ cat badfile | nc 10.9.0.5 9090
\end{lstlisting}
 

\paragraph{Reverse shell.}
We are not interested in running some pre-determined commands. We 
want to get a root shell on the target server, so we can 
type any command we want. Since we are on a remote machine,
if we simply get the server to run \texttt{/bin/sh}, we won't be able to
control the shell program. Reverse shell is a typical
technique to solve this problem. Section~\ref{sec:guildelines} provides 
detailed instructions on how to run a reverse shell.
Please modify the command string in your shellcode, so you can
get a reverse shell on the target server. 
Please include screenshots and explanation in your lab report.



% *******************************************
% SECTION
% *******************************************
\section{Task 3: Level-2 Attack} 

In this task, we are going to increase the difficulty
of the attack a little bit by not displaying an essential 
piece of the information. Our target server is 
\texttt{10.9.0.6} (the port number is still \texttt{9090}, and the 
vulnerable program is still a 32-bit program). 
Let's first send a benign message to this server. 
We will see the following messages printed out by the target container. 

\begin{lstlisting}
// On the VM (i.e., the attacker machine)
$ echo hello | nc 10.9.0.6 9090
Ctrl+C

// Messages printed out by the container
server-2-10.9.0.6 | Got a connection from 10.9.0.1
server-2-10.9.0.6 | Starting stack
server-2-10.9.0.6 | Input size: 6
server-2-10.9.0.6 | Buffer's address inside bof():     0xffffda3c
server-2-10.9.0.6 | ==== Returned Properly ====
\end{lstlisting}
 
As you can see, the server only gives out one hint, the 
address of the buffer; it does not reveal the value of the 
frame pointer. This means, the size of the buffer is unknown
to you. That makes exploiting the vulnerability more 
difficult than the Level-1 attack. 
Although the actual buffer size can be found in 
\texttt{Makefile}, you are not allowed to use that 
information in the attack, because in the real world, it is 
unlikely that you will have this file. 
To simplify the task, we do assume that the
the range of the buffer size is known.
Another fact that
may be useful to you is that, due to the memory alignment,
the value stored in the
frame pointer is always multiple of four (for 32-bit programs).


\begin{lstlisting}
Range of the buffer size (in bytes): [100, 300]
\end{lstlisting}
 

Your job is to construct one payload to exploit the buffer overflow
vulnerability on the server, and get a root shell on the target server (using
the reverse shell technique). Please be noted, you are only allowed 
to construct one payload that works for any buffer size 
within this range.  You will not get all the credits if you 
use the brute-force method, i.e., trying one buffer size
each time. The more you try, the easier it will be detected 
and defeated by the victim. That's why minimizing the number 
of trials is important for attacks. 
In your lab report, you need to describe your method, 
and provide evidences.



% *******************************************
% SECTION
% *******************************************
\section{Task 4: Level-3 Attack} 

In the previous tasks, our target servers are 32-bit 
programs. In this task, we switch to a 64-bit server 
program.  Our new target is \texttt{10.9.0.7}, which 
runs the 64-bit version of the \texttt{stack} program.  
Let's first send a hello message to this server. 
We will see the following messages printed out by the target container. 

\begin{lstlisting}
// On the VM (i.e., the attacker machine)
$ echo hello | nc 10.9.0.7 9090
Ctrl+C

// Messages printed out by the container
server-3-10.9.0.7 | Got a connection from 10.9.0.1
server-3-10.9.0.7 | Starting stack
server-3-10.9.0.7 | Input size: 6
server-3-10.9.0.7 | Frame Pointer (rbp) inside bof():  0x00007fffffffe1b0
server-3-10.9.0.7 | Buffer's address inside bof():     0x00007fffffffe070
server-3-10.9.0.7 | ==== Returned Properly ====
\end{lstlisting}

You can see the values of the frame pointer and buffer's address
become 8 bytes long (instead of 4 bytes in 32-bit programs).
Your job is to construct your payload to exploit the buffer overflow
vulnerability of the server. 
You ultimate goal is to get a root shell on 
the target server. You can use the shellcode from Task 1, but 
you need to use the 64-bit version of the shellcode. 


\paragraph{Challenges.} Compared to buffer-overflow attacks on 32-bit 
machines, attacks on 64-bit machines is more difficult. The most 
difficult part is the address. Although the x64 architecture 
supports 64-bit address space, only the address from 
\texttt{0x00} through \texttt{0x00007FFFFFFFFFFF} is allowed. That means for 
every address (8 bytes), the highest two bytes are always zeros. 
This causes a problem.

In our buffer-overflow attacks, we need to store at least one address 
in the payload, and the payload will be copied into the stack via
\texttt{strcpy()}. We know that the \texttt{strcpy()} function
will stop copying when it sees a zero. Therefore, if a zero 
appears in the middle of the payload, the content after the 
zero cannot be copied into the stack. How to solve this 
problem is the most difficult challenge in this attack. In your 
report, you need to describe how you solve this problem. 




% *******************************************
% SECTION
% *******************************************
\section{Task 5: Level-4 Attack} 

The server in this task is similar to that in Level 3, 
except that the buffer size is much smaller. From the 
following printout, you can see the distance between 
the frame pointer and the buffer's address is only about 32 bytes (the 
actual distance in the lab may be different).
In Level 3, the distance is much larger. Your goal is the same: 
get the root shell on this server. The server still takes in
517 byte of input data from the user.


\begin{lstlisting}
server-4-10.9.0.8 | Got a connection from 10.9.0.1
server-4-10.9.0.8 | Starting stack
server-4-10.9.0.8 | Input size: 6
server-4-10.9.0.8 | Frame Pointer (rbp) inside bof():  0x00007fffffffe1b0
server-4-10.9.0.8 | Buffer's address inside bof():     0x00007fffffffe190
server-4-10.9.0.8 | ==== Returned Properly ====
\end{lstlisting}
 

% *******************************************
% SECTION
% *******************************************
\section{Task 6: Experimenting with the Address Randomization}

At the beginning of this lab, we turned off one of the countermeasures,
the Address Space Layout Randomization (ASLR). In this task, we will turn
it back on, and see how it affects the attack. You can run 
the following command on your VM to enable ASLR. This change is global, and 
it will affect all the containers running inside the VM.


\begin{lstlisting}
$ sudo /sbin/sysctl -w kernel.randomize_va_space=2
\end{lstlisting}

Please send a \texttt{hello} message to the Level 1 and Level 3 servers,
and do it multiple times.
In your report, please report your observation, and explain why
ASLR makes the buffer-overflow attack more difficult. 


\paragraph{Defeating the 32-bit randomization.}
It was reported that on 32-bit Linux machines, only 19 bites can be used 
for address randomization.
That is not enough, and we can easily hit the target 
if we run the attack for sufficient number of times. For 64-bit 
machines, the number of bits used for randomization is 
significantly increased. 

In this task, we will give it a try on the 32-bit Level 1 server. 
We use the brute-force approach to attack the server repeatedly, hoping that 
the address we put in our payload can eventually be correct. 
We will use the payload from the Level-1 attack. 
You can use the following shell script to run the vulnerable program in an infinite loop. 
If you get a reverse shell, the script will stop; otherwise, it will keep running. 
If you are not so unlucky, you should be able to get a reverse shell within 10 minutes. 


\begin{lstlisting}[language=bash]
#!/bin/bash

SECONDS=0
value=0
while true; do
  value=$(( $value + 1 ))
  duration=$SECONDS
  min=$(($duration / 60))
  sec=$(($duration % 60))
  echo "$min minutes and $sec seconds elapsed."
  echo "The program has been running $value times so far."
  cat badfile | nc 10.9.0.5 9090
done
\end{lstlisting}



% *******************************************
% SECTION
% *******************************************
\section{Tasks 7: Experimenting with Other Countermeasures}

% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{Task 7.a: Turn on the StackGuard Protection}

Many compiler, such as \texttt{gcc}, implements a security mechanism called
\textit{StackGuard} to prevent buffer overflows. In the presence of this
protection, buffer overflow attacks will not work.
The provided vulnerable programs were compiled without 
enabling the StackGuard protection.
In this task, we will turn it on and see what will happen.


Please go to the \texttt{server-code} folder, remove the 
\texttt{-fno-stack-protector} flag from the 
\texttt{gcc} flag, and compile \texttt{stack.c}. 
We will only use \texttt{stack-L1}, but 
instead of running it in a container, we will directly 
run it from the command line. Let's create a file
that can cause buffer overflow, and then feed the 
content of the file \texttt{stack-L1}. Please 
describe and explain your observations. 

\begin{lstlisting}
$ ./stack-L1 < badfile 
\end{lstlisting}
 

% -------------------------------------------
% SUBSECTION
% -------------------------------------------
\subsection{Task 7.b: Turn on the Non-executable Stack Protection}

\input{part_nonexecutable_stack}


% *******************************************
% SECTION
% *******************************************
\section{Guidelines on Reverse Shell} 
\label{sec:guildelines}


\input{\commonfolder/guidelines/reverse_shell.tex}



% *******************************************
% SECTION
% *******************************************
\section{Submission}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input{\commonfolder/submission}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}
